home *** CD-ROM | disk | FTP | other *** search
/ Compendium Deluxe 1 / LSD Compendium Deluxe 1.iso / a / programming / assemblers / cas.lha / fix.Z / fix / io.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-05-10  |  20.3 KB  |  671 lines

  1. #include <stdlib.h>
  2. #include <stdio.h>
  3. #include <string.h>
  4. #include <ctype.h>
  5. #include <stdarg.h>
  6. #include "io.h"
  7. #include "op.h"
  8.  
  9. extern int Active;
  10.  
  11. /* SKIP LISTS are used to implement the symbol table */
  12.  
  13. char *CopyS(char *S) {
  14.    char *NewS;
  15.    if (S == 0) return 0;
  16.    NewS = Allocate(strlen(S) + 1);
  17.    strcpy(NewS, S);
  18.    return NewS;
  19. }
  20.  
  21. int CompS(char *A, char *B) {
  22.    if (A == 0) return (B == 0)? 0: +1;
  23.    if (B == 0) return -1;
  24.    for (; *A != '\0'; A++, B++) {
  25.       int Diff = tolower(*A) - tolower(*B);
  26.       if (Diff < 0) return -1;
  27.       if (Diff > 0) return +1;
  28.    }
  29.    return (*B == '\0')? 0: -1;
  30. }
  31.  
  32. static int Random(void) {
  33.    static byte B = 0, X = 0;
  34.    register int L = 0, D;
  35.    while (1) {
  36.       if (X == 0) X = 4, B = rand()&0xff;
  37.       D = B&3, B >>= 2, X--;
  38.       if (D) return L;
  39.       L++;
  40.    }
  41. }
  42.  
  43. #define MAX_BREADTH 16
  44. Symbol NIL;
  45. static Symbol Path[MAX_BREADTH];
  46. static int Breadth;
  47.  
  48. static Symbol Form(int B, char *Name) {
  49.    Symbol N = (Symbol)malloc(sizeof *N + B*sizeof(Symbol));
  50.    if (N == 0) fprintf(stderr, "Out of memory.\n"), exit(1);
  51.    N->Name = CopyS(Name),
  52.    N->Defined = N->Global = N->Variable = N->Address = N->Map = 0;
  53.    return N;
  54. }
  55.  
  56. #include <sys/types.h>
  57. #include <sys/timeb.h>
  58.  
  59. void SymInit(void) {
  60.    struct timeb T; int K;
  61.    ftime(&T); srand((unsigned int)(T.time ^ T.millitm)&0xffff);
  62.    NIL = Form(MAX_BREADTH - 1, 0);
  63.    for (K = 0; K < MAX_BREADTH; K++) NIL->Next[K] = NIL;
  64.    Breadth = 0;
  65. }
  66.  
  67. int Next, Value;
  68. int Line, StartLine;
  69.  
  70. Symbol LookUp(char *Name) {
  71.    int K, B; Symbol P, Q;
  72.    if (!Active) return 0;
  73.    for (K = Breadth, P = NIL; K >= 0; K--) {
  74.       Q = P->Next[K];
  75.       while (CompS(Q->Name, Name) < 0) P = Q, Q = Q->Next[K];
  76.       Path[K] = P;
  77.    }
  78.    if (CompS(Q->Name, Name) == 0) return Q;
  79.    K = Random(); if (K > Breadth) K = ++Breadth, Path[K] = NIL;
  80.    Q = Form(K, Name);
  81.    for (; K >= 0; K--) Q->Next[K] = Path[K]->Next[K], Path[K]->Next[K] = Q;
  82.    return Q;
  83. }
  84.  
  85. #define LINE_MAX 200
  86. char Text[LINE_MAX]; static char *U;
  87.  
  88. #define INCLUDE_MAX 5
  89. struct {
  90.    word Path; long Loc; int Next, Line;
  91. } IS[INCLUDE_MAX], *ISP;
  92. static FILE *InF; FILE *OutF;
  93. char **FileTab; long Files;
  94. int StartF, CurF;
  95. static int FileMax;
  96.  
  97. void FileInit(void) {
  98.    ISP = IS - 1, FileTab = 0, Files = 0, FileMax = 0;
  99. }
  100.  
  101. static byte ERRORS = 0;
  102. char InSeg = 0;
  103. void ERROR(const char *Format, ...) {
  104.    va_list AP;
  105.    if (InSeg) printf("%s: [%d] ", FileTab[StartF], StartLine);
  106.    va_start(AP, Format);
  107.    vprintf(Format, AP); putchar('\n');
  108.    va_end(AP);
  109.    if (++ERRORS >= 24) printf("Too many errors.  Aborting.\n"), exit(1);
  110.  
  111. void FATAL(const char *Format, ...) {
  112.    va_list AP;
  113.    if (InSeg) printf("%s: [%d] ", FileTab[StartF], StartLine);
  114.    va_start(AP, Format);
  115.    vprintf(Format, AP); putchar('\n');
  116.    va_end(AP);
  117.    exit(1);
  118. }
  119.  
  120. void CHECK(void) {
  121.    if (ERRORS > 0) printf("Errors present.  Assembly stopped.\n"), exit(1);
  122. }
  123.  
  124. byte GetB(FILE *FP) {
  125.    int A;
  126.    A = fgetc(FP); if (A == EOF) FATAL("Unexpected EOF.");
  127.    return A&0xff;
  128. }
  129.  
  130. word GetW(FILE *FP) {
  131.    int A, B;
  132.    A = fgetc(FP); if (A == EOF) FATAL("Unexpected EOF.");
  133.    B = fgetc(FP); if (B == EOF) FATAL("Unexpected EOF.");
  134.    return (A&0xff) << 8 | B&0xff;
  135. }
  136.  
  137. unsigned long GetL(FILE *FP) {
  138.    int A, B, C, D;
  139.    A = fgetc(FP); if (A == EOF) FATAL("Unexpected EOF.");
  140.    B = fgetc(FP); if (B == EOF) FATAL("Unexpected EOF.");
  141.    C = fgetc(FP); if (C == EOF) FATAL("Unexpected EOF.");
  142.    D = fgetc(FP); if (D == EOF) FATAL("Unexpected EOF.");
  143.    return (A&0xff) << 24 | (B&0xff) << 16 | (C&0xff) << 8 | D&0xff;
  144. }
  145.  
  146. void PutB(byte B, FILE *FP) { fputc(B, FP); }
  147.  
  148. void PutW(word W, FILE *FP) {
  149.    char A = (W >> 8)&0xff, B = W&0xff;
  150.    fputc(A, FP), fputc(B, FP);
  151. }
  152.  
  153. void PutL(unsigned long L, FILE *FP) {
  154.    char A = (L >> 24)&0xff, B = (L >> 16)&0xff, C = (L >> 8)&0xff, D = L&0xff;
  155.    fputc(A, FP), fputc(B, FP), fputc(C, FP), fputc(D, FP);
  156. }
  157.  
  158. void *Allocate(unsigned Size) {
  159.    void *X;
  160.    if (Size == 0) return 0;
  161.    X = malloc(Size); if (X == 0) FATAL("Out of memory.");
  162.    return X;
  163. }
  164.  
  165. void OpenF(char *Name) {
  166.    if (!Active) return;
  167.    if (ISP >= IS + INCLUDE_MAX - 1) FATAL("Too many nested include files.");
  168.    if (ISP >= IS) {
  169.       ISP->Loc = ftell(InF);
  170.       if (ISP->Loc == -1L)
  171.          FATAL("Could not save %s's position.", FileTab[CurF]);
  172.       fclose(InF);
  173.       ISP->Next = Next, ISP->Line = Line, ISP->Path = CurF;
  174.    }
  175.    if (Files >= FileMax) {
  176.       FileMax += 4;
  177.       FileTab = (char **)realloc(FileTab, FileMax * sizeof *FileTab);
  178.       if (FileTab == 0) FATAL("Out of memory.");
  179.    }
  180.    ISP++, CurF = Files, FileTab[Files++] = CopyS(Name);
  181.    StartLine = Line = 1;
  182.    InF = fopen(Name, "r");
  183.    if (InF == 0) FATAL("Cannot open %s", Name);
  184.    Next = fgetc(InF);
  185. }
  186.  
  187. #define SEG_MAX 0x20
  188. struct Segment SegTab[SEG_MAX], *SegP;
  189. unsigned long LOC;
  190.  
  191. #define GAP_MAX 0x100
  192. struct Gap GapTab[GAP_MAX], *GapP;
  193.  
  194. struct AddrCard AddrTab[TYPES] = {
  195.    { 0, 0xffff, 1 },  /* CODE */
  196.    { 0, 0xffff, 0 },  /* XDATA */
  197.    { 0, 0xff, 0 },    /* DATA */
  198.    { 0x80, 0xff, 0 }, /* SFR */
  199.    { 0, 0xff, 0 }     /* BIT */
  200. };
  201. static struct AddrCard *AdP;
  202.  
  203. Symbol Sym;
  204.  
  205. static Symbol BTab[10], FTab[10];
  206. static Symbol MakeLabel(void) {
  207.    static unsigned long LAB = 0L; static char Buf[10];
  208.    sprintf(Buf, "#%x", LAB++);
  209.    return LookUp(Buf);
  210. }
  211.  
  212. void SegInit(void) {
  213.    int I, D;
  214.    for (SegP = SegTab, AdP = AddrTab, I = 0; I < TYPES; AdP++, I++, SegP++) {
  215.       if (SegP >= SegTab + SEG_MAX) FATAL("Too many segments.");
  216.       SegP->Type = I, SegP->Rel;
  217.       SegP->Base = 0, SegP->Size = 0, SegP->Loc = ftell(OutF);
  218.    }
  219.    AdP = AddrTab; InSeg = 1;
  220.    SegP->Type = 0, SegP->Rel = 1,
  221.    SegP->Line = StartLine, SegP->File = StartF,
  222.    SegP->Base = 0, SegP->Size = 0, SegP->Loc = ftell(OutF);
  223.    LOC = 0;
  224.    for (D = 0; D < 10; D++) BTab[0] = FTab[0] = 0;
  225.    GapP = GapTab;
  226. }
  227.  
  228. void StartSeg(byte Type, byte Rel, word Base) {
  229.    int D;
  230.    if (!Active) return;
  231.    if (SegP >= SegTab + SEG_MAX) FATAL("Too many segments.");
  232.    if (Type > sizeof AddrTab/sizeof *AddrTab)
  233.       FATAL("Undefined segment type.");
  234.    AdP = AddrTab + Type;
  235.    if (!Rel && (Base < AdP->Lo || Base > AdP->Hi))
  236.       FATAL("Address %u out of range", Base);
  237.    InSeg = 1;
  238.    SegP->Type = Type, SegP->Rel = Rel,
  239.    SegP->Line = StartLine, SegP->File = StartF,
  240.    SegP->Base = Base, SegP->Size = 0, SegP->Loc = ftell(OutF);
  241.    LOC = 0;
  242.    for (D = 0; D < 10; D++) BTab[0] = FTab[0] = 0;
  243. }
  244.  
  245. void EndSeg(void) {
  246.    int D;
  247.    if (!Active) return;
  248.    for (D = 0; D < 10; D++)
  249.       if (FTab[D] != 0) ERROR("Undefined label %d", D);
  250.    SegP->Size = (word)LOC;
  251.    if (SegP->Size > 0) SegP++;
  252.    InSeg = 0;
  253. }
  254.  
  255. void PByte(byte B) {
  256.    unsigned long Addr;
  257.    if (!Active) return;
  258.    if (!AdP->ReadOnly) FATAL("Attempting to write to a non-code segment.");
  259.    LOC++; Addr = SegP->Base + LOC;
  260.    if (!SegP->Rel && Addr > AdP->Hi + 1) FATAL("Address %u out of range", Addr);
  261.    fputc(B, OutF);
  262. }
  263.  
  264. void PString(char *S) {
  265.    if (!Active) return;
  266.    for (; *S != '\0'; S++) PByte(*S);
  267. }
  268.  
  269. void Space(word Rel) {
  270.    unsigned long Addr;
  271.    if (!Active) return;
  272.    if (AdP->ReadOnly) {
  273.       if (GapP >= GapTab + GAP_MAX) FATAL("Too many gaps.");
  274.       GapP->Seg = SegP, GapP->Offset = LOC, GapP->Size = Rel;
  275.       GapP++;
  276.    }
  277.    LOC += Rel;
  278.    Addr = SegP->Base + LOC;
  279.    if (!SegP->Rel && Addr > AdP->Hi + 1) FATAL("Address %u out of range", Addr);
  280. }
  281.  
  282. /* A hasty bug fix: accounts for the fact that the memory images stored in
  283.    files exclude gaps.
  284.  */
  285. long SegTell(Segment Seg, word Offset) {
  286.    long L = Seg->Loc + Offset; Gap G;
  287.    for (G = GapTab; G < GapP; G++)
  288.       if (G->Seg == Seg && G->Offset < Offset) L -= G->Size;
  289.    return L;
  290. }
  291.  
  292. static void Get(void) {
  293.    int Ch;
  294.    if (Next == EOF) {
  295.       while (Next == EOF && ISP > IS) {
  296.          fclose(InF); ISP--;
  297.          Next = ISP->Next, Line = ISP->Line, CurF = ISP->Path;
  298.          InF = fopen(FileTab[CurF], "r");
  299.          if (InF == 0) FATAL("Cannot reopen %s", FileTab[CurF]);
  300.          if (fseek(InF, ISP->Loc, SEEK_SET) != 0) {
  301.             fclose(InF);
  302.             FATAL("Could not restore %s's position.", FileTab[CurF]);
  303.          }
  304.       }
  305.       if (Next == EOF) fclose(InF), Next = 0;
  306.       *U++ = ' ';
  307.    } else {
  308.       if (Next == '\n') Line++;
  309.       *U++ = Next; Next = fgetc(InF);
  310.    }
  311. }
  312.  
  313. typedef struct {
  314.    char *Name; Lexical Tag; int Value;
  315. } Card;
  316. static Card Reserved[] = {
  317.    { "ds", RB, 0 }, { "rb", RB, 0 }, { "rw", RW, 0 },
  318.    { "byte", DB, 0 }, { "word", DW, 0 }, { "db", DB, 0 }, { "dw", DW, 0 },
  319.    { "seg", SEG, 0 }, { "end", END, 0 },
  320.    { "org", ORG, 0 }, { "at", ORG, 0 }, { "equ", EQU, 0 }, { "set", SET, 0 },
  321.    { "include", INCLUDE, 0 }, { "global", GLOBAL, 0 }, { "public", GLOBAL, 0 },
  322.    { "extern", EXTERN, 0 }, { "if", IF, 0 }, { "else", ELSE, 0 },
  323.    { "high", HIGH, 0 }, { "low", LOW, 0 }, { "by", BY, 0 },
  324.    { "code", TYPE, CODE }, { "xdata", TYPE, XDATA },
  325.    { "bit", TYPE, BIT }, { "sfr", TYPE, SFR }, { "data", TYPE, DATA },
  326.    { "a", REGISTER, ACC }, { "ab", REGISTER, AB }, { "c", REGISTER, CY },
  327.    { "dptr", REGISTER, DPTR }, { "pc", REGISTER, PC },
  328.    { "r0", REGISTER, R0 }, { "r1", REGISTER, R1 },
  329.    { "r2", REGISTER, R2 }, { "r3", REGISTER, R3 },
  330.    { "r4", REGISTER, R4 }, { "r5", REGISTER, R5 },
  331.    { "r6", REGISTER, R6 }, { "r7", REGISTER, R7 }
  332. };
  333.  
  334. #define ELEMENTS(Arr) (sizeof(Arr)/sizeof(Arr[0]))
  335.  
  336. static Lexical FindKey(char *Name) {
  337.    Code *CP; Card *C;
  338.    static Card *EndR = Reserved + ELEMENTS(Reserved);
  339.    for (CP = CodeTab; CP->Name != 0; CP++)
  340.       if (CompS(Name, CP->Name) == 0) {
  341.          Value = CP - CodeTab; return MNEMONIC;
  342.       }
  343.    for (C = Reserved; C < EndR; C++)
  344.       if (CompS(Name, C->Name) == 0) {
  345.          Value = C->Value; return C->Tag;
  346.       }
  347.    Sym = LookUp(Name);
  348.    return SYMBOL;
  349. }
  350.  
  351. typedef struct {
  352.    char *Name; byte Type; word Val;
  353. } ValCard;
  354. static ValCard ValTab[] = {
  355. /* Special function registers */
  356.    { "P0", SFR, 0x80 }, { "P1", SFR, 0x90 },
  357.    { "P2", SFR, 0xa0 }, { "P3", SFR, 0xb0 },
  358.    { "PCON", SFR, 0x87 }, { "TCON", SFR, 0x88 }, { "TMOD", SFR, 0x89 },
  359.    { "SCON", SFR, 0x98 }, { "SBUF", SFR, 0x99 },
  360.    { "IE",   SFR, 0xa8 }, { "IP",   SFR, 0xb8 },
  361.    { "TL0", SFR, 0x8a }, { "TL1", SFR, 0x8b },
  362.    { "TH0", SFR, 0x8c }, { "TH1", SFR, 0x8d },
  363.    { "SP",   SFR, 0x81 }, { "DPL",  SFR, 0x82 }, { "DPH",  SFR, 0x83 },
  364.    { "PSW",  SFR, 0xd0 }, { "ACC",  SFR, 0xe0 }, { "B",    SFR, 0xf0 },
  365. /* Special funcgtion register bits */
  366.    { "RI",  BIT, 0x98 }, { "TI",  BIT, 0x99 },    /* SCON */
  367.    { "RB8", BIT, 0x9a }, { "TB8", BIT, 0x9b },
  368.    { "REN", BIT, 0x9c }, { "SM2", BIT, 0x9d },
  369.    { "SM1", BIT, 0x9e }, { "SM0", BIT, 0x9f },
  370.    { "RXD",  BIT, 0xb0 }, { "TXD",  BIT, 0xb1 },  /* Port 3 */
  371.    { "INT0", BIT, 0xb2 }, { "INT1", BIT, 0xb3 },
  372.    { "T0",   BIT, 0xb4 }, { "T1",   BIT, 0xb5 },
  373.    { "WR",   BIT, 0xb6 }, { "RD",   BIT, 0xb7 },
  374.    { "P",   BIT, 0xd0 }, { "OV",  BIT, 0xd2 },    /* PSW */
  375.    { "RS0", BIT, 0xd3 }, { "RS1", BIT, 0xd4 },
  376.    { "F0",  BIT, 0xd5 }, { "AC",  BIT, 0xd6 }, { "CY",  BIT, 0xd7 },
  377.    { "IT0", BIT, 0x88 }, { "IE0", BIT, 0x89 },    /* TCON */
  378.    { "IT1", BIT, 0x8a }, { "IE1", BIT, 0x8b },
  379.    { "TR0", BIT, 0x8c }, { "TF0", BIT, 0x8d },
  380.    { "TR1", BIT, 0x8e }, { "TF1", BIT, 0x8f },
  381.    { "EX0", BIT, 0xa8 }, { "ET0", BIT, 0xa9 },    /* IE */
  382.    { "EX1", BIT, 0xaa }, { "ET1", BIT, 0xab },
  383.    { "ES",  BIT, 0xac }, { "EA",  BIT, 0xaf },
  384.    { "PX0", BIT, 0xb8 }, { "PT0", BIT, 0xb9 },    /* IP */
  385.    { "PX1", BIT, 0xba }, { "PT1", BIT, 0xbb }, { "PS",  BIT, 0xbc }
  386. };
  387.  
  388. void RegInit(void) {
  389.    ValCard *V; Symbol Sym;
  390.    static ValCard *EndV = ValTab + ELEMENTS(ValTab);
  391.    for (V = ValTab; V < EndV; V++) {
  392.       Sym = LookUp(V->Name);
  393.       Sym->Defined = Sym->Address = 1;
  394.       Sym->Seg = &SegTab[V->Type], Sym->Offset = V->Val;
  395.    }
  396. }
  397.  
  398. #define isoctal(Ch) (isdigit(Ch) && Ch < '8')
  399. #define isx(Ch) (tolower(Ch) == 'x' || tolower(Ch) == 'h')
  400. #define isq(Ch) (tolower(Ch) == 'q' || tolower(Ch) == 'o')
  401.  
  402. char InExp = 0, InSemi = 0;
  403. Lexical OldL;
  404. #define Ret(Token) return (*U = '\0', OldL = (Token))
  405.  
  406. Lexical Scan(void) {
  407.    char *S; int Bad;
  408. Start:
  409.    U = Text;
  410.    if (isalpha(Next) || Next == '_') {
  411.       while (isalnum(Next) || Next == '_') Get();
  412.       Ret(FindKey(Text));
  413.    } else if (isdigit(Next)) {
  414.       char Ch = Next; Get();
  415.       if (Ch == '0' && isx(Next)) {
  416.          do Get(); while (isxdigit(Next));
  417.          goto RetHex;
  418.       }
  419.       if (Next == ':' && !InExp) {
  420.          char D = *Text - '0';
  421.          if (Active) {
  422.             Sym = BTab[D] = (FTab[D] == 0)? MakeLabel(): FTab[D];
  423.             FTab[D] = 0;
  424.             Sym->Global = 0, Sym->Defined = Sym->Address = Sym->Variable = 1,
  425.             Sym->Seg = SegP, Sym->Offset = (word)LOC;
  426.          } else Sym = 0;
  427.          Ret(SYMBOL);
  428.       }
  429.       while (isxdigit(Next)) Get();
  430.       if (isx(Next)) { Get(); goto RetHex; }
  431.       if (isq(Next)) { Get(); goto RetOct; }
  432.       if (U - Text == 2) {
  433.          if (tolower(Text[1]) == 'b') {
  434.             char D = *Text - '0';
  435.             if (Active) {
  436.                Sym = BTab[D];
  437.                if (Sym == 0) {
  438.                   BTab[D] = Sym = MakeLabel();
  439.                   ERROR("Undefined local symbol %cb", D);
  440.                   Sym->Global = Sym->Defined = 0,
  441.                   Sym->Address = Sym->Variable = 1,
  442.                   Sym->Seg = SegP, Sym->Offset = 0;
  443.                }
  444.             } else Sym = 0;
  445.             Ret(SYMBOL);
  446.          } else if (tolower(Text[1]) == 'f') {
  447.             char D = *Text - '0';
  448.             if (Active) {
  449.                if (FTab[D] == 0) FTab[D] = MakeLabel();
  450.                Sym = FTab[D];
  451.             } else Sym = 0;
  452.             Ret(SYMBOL);
  453.          }
  454.       }
  455.       if (tolower(U[-1]) == 'b') goto RetBin;
  456.       if (tolower(U[-1]) == 'd' || *Text != '0') goto RetDec;
  457.       if (U == Text) { Value = 0; Ret(NUMBER); }
  458.       if (isx(Text[1])) goto RetHex;
  459.       if (tolower(Text[1]) == 'b') goto RetBin;
  460.       goto RetDec;
  461. RetBin:
  462.       S = Text;
  463.       if (tolower(U[-1]) == 'b') U--;
  464.       else if (U >= S + 2 && S[0] == '0' && tolower(S[1]) == 'b') S += 2;
  465.       for (Bad = 0, Value = 0; S < U; S++) {
  466.          int D = *S - '0';
  467.          if (!isdigit(*S) || D >= 2) Bad++, D = 0;
  468.          Value = (Value << 1) | D;
  469.       }
  470.       if (Bad) ERROR("Binary number has non-binary digits.");
  471.       Ret(NUMBER);
  472. RetOct:
  473.       if (isq(U[-1])) U--;
  474.       for (Bad = 0, Value = 0, S = Text; S < U; S++) {
  475.          int D = *S - '0';
  476.          if (!isdigit(*S) || D >= 010) Bad++, D = 0;
  477.          Value = (Value << 3) | D;
  478.       }
  479.       if (Bad) ERROR("Octal number has non-octal digits.");
  480.       Ret(NUMBER);
  481. RetDec:
  482.       if (tolower(U[-1]) == 'd') U--;
  483.       for (Bad = 0, Value = 0, S = Text; S < U; S++) {
  484.          int D = *S - '0';
  485.          if (!isdigit(*S)) Bad++, D = 0;
  486.          Value = 10*Value + D;
  487.       }
  488.       if (Bad) ERROR("Decimal number has non-decimal digits.");
  489.       Ret(NUMBER);
  490. RetHex:
  491.       S = Text;
  492.       if (isx(U[-1])) U--;
  493.       else if (U >= S + 2 && S[0] == '0' && isx(S[1])) S += 2;
  494.       for (Value = 0; S < U; S++) {
  495.          Value <<= 4, Value += isdigit(*S)? *S - '0': tolower(*S) - 'a' + 10;
  496.       }
  497.       Ret(NUMBER);
  498.    }
  499.    switch (Next) {
  500.       case ';': switch (Get(), Next) {
  501.          case ';':
  502.             while (Next != '\n') {
  503.                if (Next == EOF) FATAL("Unexpected EOF inside ;; comment.");
  504.                Next = fgetc(InF);
  505.             }
  506.             Get();
  507.             if (!InSemi) goto Start;
  508.          default: Ret(SEMI);
  509.       }
  510.       break;
  511.       case '/': switch (Get(), Next) {
  512.          case '/':
  513.             while (Next != '\n') {
  514.                if (Next == EOF) FATAL("Unexpected EOF inside // comment.");
  515.                Next = fgetc(InF);
  516.             }
  517.             Get();
  518.             if (!InSemi) goto Start;
  519.          Ret(SEMI);
  520.          case '*': {
  521.             int Line0 = Line;
  522.             Next = fgetc(InF);
  523.             while (Next != EOF) {
  524.                if (Next == '*') {
  525.                   while (Next == '*') Next = fgetc(InF);
  526.                   if (Next == '/') {
  527.                      Next = fgetc(InF);
  528.                      if (Line <= Line0 || !InSemi) goto Start;
  529.                      Ret(SEMI);
  530.                   }
  531.                } else {
  532.                   if (Next == '\n') Line++; Next = fgetc(InF);
  533.                }
  534.             }
  535.             FATAL("Unexpected EOF inside comment.");
  536.          }
  537.          default: Ret(DIV);
  538.       }
  539.       case '\'':
  540.      Get();
  541.          if (Next == '\'') {
  542.             ERROR("Empty character constant."); Get(); Value = 0; Ret(NUMBER);
  543.          }
  544.      if (Next == '\\') {
  545.             int I;
  546.         Get();
  547.         if (isoctal(Next)) {
  548.            for (Value = 0; isoctal(Next); Get())
  549.                   Value <<= 3, Value += Next - '0';
  550.         } else if (tolower(Next) == 'x') {
  551.            Get();
  552.                if (!isxdigit(Next)) {
  553.                   ERROR("Bad hexadecimal character.");
  554.                   Value = 'x';
  555.                } else for (I = 0; I < 2 && isxdigit(Next); I++, Get()) {
  556.                   Value <<= 4;
  557.                   Value += isdigit(Next)? Next - '0': tolower(Next) - 'a' + 10;
  558.                }
  559.         } else {
  560.                switch (Next) {
  561.                   case 'a': Value = 0x07; break;
  562.                   case 'b': Value = 0x08; break;
  563.                   case 't': Value = 0x09; break;
  564.                   case 'n': Value = 0x0a; break;
  565.                   case 'v': Value = 0x0b; break;
  566.                   case 'f': Value = 0x0c; break;
  567.                   case 'r': Value = 0x0d; break;
  568.                   default: Value = Next; break;
  569.                }
  570.                Get();
  571.             }
  572.      } else Value = Next, Get();
  573.      if (Next != '\'') ERROR("Missing a ' in character constant.");
  574.          else Get();
  575.       Ret(NUMBER);
  576.       case '"':
  577.          Next = fgetc(InF);
  578.          while (Next != '\"') {
  579.             if (Next == EOF) FATAL("Unexpected EOF inside string.");
  580.             else if (Next == '\\') {
  581.                Next = fgetc(InF);
  582.                if (Next == EOF) FATAL("Unexpected EOF inside string.");
  583.            if (isoctal(Next)) {
  584.                   char Value = 0;
  585.                   while (isoctal(Next)) {
  586.                      Value = (Value << 3) + (Next - '0');
  587.                      Next = fgetc(InF);
  588.                   }
  589.                   *U++ = Value;
  590.            } else if (tolower(Next) == 'x') {
  591.                   char Value;
  592.                   Next = fgetc(InF);
  593.                   if (!isxdigit(Next)) Value = 'x';
  594.           else while (isxdigit(Next)) {
  595.                      Value <<= 4;
  596.                      Value += isdigit(Next)? Next - '0': tolower(Next) - 'a' + 10;
  597.                      Next = fgetc(InF);
  598.                   }
  599.                   *U++ = Value;
  600.            } else {
  601.                   if (Next == '\n') Line++;
  602.                   switch (Next) {
  603.                      case 'a': *U++ = '\a'; break;
  604.                      case 'b': *U++ = '\b'; break;
  605.                      case 't': *U++ = '\t'; break;
  606.                      case 'n': *U++ = '\n'; break;
  607.                      case 'v': *U++ = '\v'; break;
  608.                      case 'f': *U++ = '\f'; break;
  609.                      case 'r': *U++ = '\r'; break;
  610.                      default: *U++ = Next; break;
  611.                   }
  612.                   Next = fgetc(InF);
  613.                }
  614.         } else {
  615.                if (Next == '\n') Line++;
  616.                *U++ = Next; Next = fgetc(InF);
  617.             }
  618.          }
  619.          Next = fgetc(InF);
  620.       Ret(STRING);
  621.       case '<': switch (Get(), Next) {
  622.      case '=': Get(); Ret(LE);
  623.      case '<': Get(); Ret(SHL);
  624.          default: Ret(LT);
  625.       }
  626.       case '>': switch (Get(), Next) {
  627.      case '=': Get(); Ret(GE);
  628.      case '>': Get(); Ret(SHR);
  629.      default: Ret(GT);
  630.       }
  631.       case '&': switch (Get(), Next) {
  632.      case '&': Get(); Ret(AND_AND);
  633.      default: Ret(AND);
  634.       }
  635.       case '|': switch (Get(), Next) {
  636.      case '|': Get(); Ret(OR_OR);
  637.      default: Ret(OR);
  638.       }
  639.       case '=': switch (Get(), Next) {
  640.      case '=': Get(); Ret(EQ);
  641.      default: Ret(SET);
  642.       }
  643.       case '!': switch (Get(), Next) {
  644.      case '=': Get(); Ret(NE);
  645.      default: Ret(NOT_NOT);
  646.       }
  647.       case '\n': Get(); if (!InSemi) goto Start; Ret(SEMI);
  648.       case '^': Get(); Ret(XOR);
  649.       case '+': Get(); Ret(PLUS);
  650.       case '-': Get(); Ret(MINUS);
  651.       case '*': Get(); Ret(MULT);
  652.       case '%': Get(); Ret(MOD);
  653.       case '@': Get(); Ret(AT);
  654.       case '#': Get(); Ret(POUND);
  655.       case '$': Get(); Ret(DOLLAR);
  656.       case '.': Get(); Ret(DOT);
  657.       case '~': Get(); Ret(NOT);
  658.       case ',': Get(); Ret(COMMA);
  659.       case ':': Get(); Ret(COLON);
  660.       case '?': Get(); Ret(QUEST);
  661.       case '{': Get(); Ret(LCURL);
  662.       case '}': Get(); Ret(RCURL);
  663.       case '(': Get(); Ret(LPAR);
  664.       case ')': Get(); Ret(RPAR);
  665.       case 0: Ret(0);
  666.       default: Get(); goto Start;
  667.    }
  668. }
  669.  
  670.